#include "golomb.h"
#include "invocation.h"
#include "log.h"
#include "gerror.h"
#include "coder.h"
#include "rawdata.h"
#include "compresseddata.h"
#include <Python.h>
#include <csignal>
#include <cstdlib>

using namespace std;

Golomb::Golomb(Invocation args) :
		analyzer(args), coder(args.debug), tmpPath("/tmp/gol-assert.tmp")
{
	logger.provideArgs(args);

	if (!args.decode)
	{
		analyzer.printStats();
		for (unsigned int path_i = 0; path_i < args.inPaths.size(); path_i++)
		{
			for (unsigned int w_i = 0; w_i < args.wordSize.size(); w_i++)
			{
				for (unsigned int m_i = 0; m_i < args.M.size(); m_i++)
				{

					int M = args.M[m_i];
					int W = args.wordSize[w_i];
					string& in = args.inPaths[path_i];
					string& out = args.outPaths[path_i];
					bool adapt = !(bool) M;
					encode(in, out, M, W);

					int ignore;
					if(args.asserting)
						decode(out, tmpPath, ignore, ignore);
					bool assertion = analyzer.assertCoding(in, tmpPath);

					analyzer.accumulate(in, out, M, W, assertion, adapt);
					analyzer.printRow();
				}
			}
		}
	}
	else
	{
		for (unsigned int i = 0; i < args.inPaths.size(); i++)
		{
			string& in = args.inPaths[i];
			string& out = args.outPaths[i];
			int M = -1;
			int W = -1;

			decode(in, out, M, W);
		}

	}
}

void Golomb::encode(std::string& in, std::string& out, int& M, int& W)
{
	RawDataInput input(in, W);
	if (M == 0)
	{
		M = coder.adapt(input.dictBuilder);
	}
	CompressedDataOutput output(out, M, W, input.dictionary, input.lastSize);
	coder.encode(input, output, M);
	output.commit();
}

void Golomb::decode(std::string& in, std::string& out, int& M, int& W)
{
	CompressedDataInput input(in);
	RawDataOutput output(out, input.wordSize, input.dictionary, input.lastSize);
	coder.decode(input, output, input.M);
	output.commit();

	M = input.M;
	W = input.wordSize;
}

int main(int argc, char **argv)
{
	signal(SIGINT, onExit);
	signal(SIGTERM, onExit);
	try
	{
		Py_Initialize();
		logger.init();
		Golomb(Invocation(argc, argv));
	} catch (exception& e)
	{
		logger.error(e);
	}
	logger.reset();
	Py_Finalize();
	return 0;
}

void onExit(int sig)
{
	exit(1);
}
